0bc01f
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2018 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,7 +16,8 @@
 
 package org.springframework.remoting.rmi;
 
-import java.rmi.NoSuchObjectException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
 import java.util.Properties;
@@ -25,6 +26,8 @@
import javax.naming.NamingException;
 import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.jndi.JndiTemplate;
+import org.springframework.lang.Nullable;
+import org.springframework.util.ReflectionUtils;
 
 /**
  * Service exporter which binds RMI services to JNDI.
@@ -66,6 +69,27 @@
import org.springframework.jndi.JndiTemplate;
  */
 public class JndiRmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean {
 
+	@Nullable
+	private static Method exportObject;
+
+	@Nullable
+	private static Method unexportObject;
+
+	static {
+		try {
+			Class<?> portableRemoteObject =
+					JndiRmiServiceExporter.class.getClassLoader().loadClass("javax.rmi.PortableRemoteObject");
+			exportObject = portableRemoteObject.getMethod("exportObject", Remote.class);
+			unexportObject = portableRemoteObject.getMethod("unexportObject", Remote.class);
+		}
+		catch (Throwable ex) {
+			// java.corba module not available on JDK 9+
+			exportObject = null;
+			unexportObject = null;
+		}
+	}
+
+
 	private JndiTemplate jndiTemplate = new JndiTemplate();
 
 	private String jndiName;
@@ -116,6 +140,7 @@
public class JndiRmiServiceExporter extends RmiBasedExporter implements Initiali
 
 		// Initialize and cache exported object.
 		this.exportedObject = getObjectToExport();
+		invokePortableRemoteObject(exportObject);
 
 		rebind();
 	}
@@ -136,11 +161,31 @@
public class JndiRmiServiceExporter extends RmiBasedExporter implements Initiali
 	 * Unbind the RMI service from JNDI on bean factory shutdown.
 	 */
 	@Override
-	public void destroy() throws NamingException, NoSuchObjectException {
+	public void destroy() throws NamingException, RemoteException {
 		if (logger.isInfoEnabled()) {
 			logger.info("Unbinding RMI service from JNDI location [" + this.jndiName + "]");
 		}
 		this.jndiTemplate.unbind(this.jndiName);
+		invokePortableRemoteObject(unexportObject);
+	}
+
+
+	private void invokePortableRemoteObject(@Nullable Method method) throws RemoteException {
+		if (method != null) {
+			try {
+				method.invoke(null, this.exportedObject);
+			}
+			catch (InvocationTargetException ex) {
+				Throwable targetEx = ex.getTargetException();
+				if (targetEx instanceof RemoteException) {
+					throw (RemoteException) targetEx;
+				}
+				ReflectionUtils.rethrowRuntimeException(targetEx);
+			}
+			catch (Throwable ex) {
+				throw new IllegalStateException("PortableRemoteObject invocation failed", ex);
+			}
+		}
 	}
 
 }
